#include <sys_config.h>
#include <retcode.h>
#include <types.h>
#include <osal/osal.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
//#include <bus/sci/sci.h>
//#include <hld/hld_dev.h>
#include <hld/pan/pan_dev.h>
#include <hld/pan/pan.h>
#include <hld/pan/pan_key.h>
//#include <api/libtsi/sec_tdt2.h>
//#include <api/libpub29/lib_pub27.h>
#include <hld/pan/pan_dev.h>
#include <hld/pan/pan.h>

//#include "sys_config.h"
#include "copper_common/system_data.h"
#include "control.h"
#include "key.h"
#include "vkey.h"
#include "win_com.h"
//#include "aov_custom_uart.h" /*steven fix*/
#include "copper_common/com_api.h"
#include "win_com_popup.h"

#include <api/libupg/usb_upgrade.h>

//////////////////////////////////////////////////////////////////
//steven(2008/12/08): TT#558 Factory test functions.[Start]

extern CONTAINER  g_win_welcom;
extern CONTAINER  g_win_mainmenu;
extern CONTAINER g_win_factory_test;
extern CONTAINER win_usbupg_con;

extern BOOL b_fast_upgrade=FALSE;

//extern UINT16 usb_fastfile_cnt=0;
//extern UINT16 usb_mcufile_cnt=0;

#define MAX_HISTORY 6
static char key_history[MAX_HISTORY+1];
static char History_Idx=0;
static BOOL KeyEnabled = FALSE;

extern UINT8 aov_fast_usbupg_start_proc(USBUPG_BLOCK_TYPE block_type);

BOOL isFactoryMode = FALSE;  //for not show yes/no confrim message and start to scan.

void Factory_Mode_Set_Flag( BOOL flag  )
{
	isFactoryMode = flag;
}

BOOL Factory_Mode_Get_Flag(void)
{
	return isFactoryMode;
}

/***************************
*    Auto power off test 
****************************/
//static ID poweroff_timer_id = OSAL_INVALID_ID;
static int factory_auto_power_off_timeout = 0;

void Factory_PowerOff_Timer_Handler()
{
	char factory_auto_power_of_msg[10];

	while (factory_auto_power_off_timeout--)
	{
		sprintf(factory_auto_power_of_msg," -%d-", factory_auto_power_off_timeout);
		key_pan_display(factory_auto_power_of_msg, 4);

		win_compopup_init(WIN_POPUP_TYPE_SMSG);
		win_compopup_set_msg_ext(factory_auto_power_of_msg,NULL, NULL);
		win_compopup_open();
		osal_task_sleep(1000);
		win_compopup_close();
	}

	key_pan_display(" BYE", 4);
	win_compopup_init(WIN_POPUP_TYPE_SMSG);
	win_compopup_set_msg_ext("Shutdown",NULL, NULL);
	win_compopup_open();
	osal_task_sleep(1000);
       
}

void Auto_Power_Off_Test(void)
{
	Factory_PowerOff_Timer_Handler();
	ap_send_msg(CTRL_MSG_SUBTYPE_CMD_SLEEP, (UINT32)0, TRUE);
	//poweroff_timer_id = api_start_timer("5_sec", 1000, Factory_PowerOff_Timer_Handler);
}

/*****************************
*          Factory lock test.
*****************************/
static ID locktest_id = OSAL_INVALID_ID;
static void Factory_Lock_Test(void);
static int fty_lk_n = 0;
#define LOCK_TEST_TIMER 1000 /*for 1 sec*/

void Start_Factory_Lock_Test(void)
{
	api_stop_timer(&locktest_id);
	//Factory_Lock_Test();
	locktest_id = api_start_cycletimer("lock_test", LOCK_TEST_TIMER, Factory_Lock_Test);
}

void Stop_Factory_Lock_Test(void)
{
	api_stop_timer(&locktest_id);
}

void Factory_Lock_Test( void )
{
    char str[2] = "";
    char seg_string[5];
    UINT8 lock, quality, temp;

	nim_get_lock(g_nim_dev, &lock);
    nim_get_SNR(g_nim_dev, &quality);
                
    switch( lock )
    {
      	case 1:
           	str[0] = 'L';
			if( fty_lk_n % 2 == 0 )
            	str[1] = '-';
            else
            	str[1] = ' ';  
                                
            fty_lk_n++;
            if( fty_lk_n >= 2 )
            	fty_lk_n = 0;
            break;
                                
        case 0:
            str[0] = 'F'; 
            str[1] = ' ';  
			quality = 0;
            break;
                                
        default:
            str[0] = '-';  
            str[1] = ' ';  
            quality = 0;
            break;
    }
                
    if( quality >= 100 )
    	quality = 99;
                
    sprintf( seg_string, "%c%c%d%d", str[0], str[1], quality/10, quality%10 );
    key_pan_display( seg_string , 4);
    //CHENGYU_PRINTF("Factory_Lock_Test ==> (%s)\n", seg_string);
}

/*******************************************************************************
*	steven: for factory test.
*******************************************************************************/
void Aov_Factory_Load_Default( void )
{
    UINT32 chunk_id, default_db_addr, default_db_len;
    UINT8 back_saved;
    POBJECT_HEAD top_win, win_menu;

	//vpo_win_onoff(g_vpo_dev, FALSE);//weber@20091005 Close menu logo when run "Exit/Set to Default" in factory menu//api_stop_play(0);
	api_stop_play(0);
	ap_clear_all_menus();
	
	win_compopup_init(WIN_POPUP_TYPE_SMSG);
	win_compopup_set_msg_ext("Loading defualt data...",NULL, NULL);
	win_compopup_open();
        
	chunk_id = (USERDB_CHUNID_TYPE|0x0100);
    //api_get_chuck_addlen(chunk_id, &default_db_addr, &default_db_len); //ChengYu@ Build error, nedd check
    key_pan_display("DEFt", 4);   
    set_default_value(DEFAULT_ALL_PROG,default_db_addr + 16);
        
    sys_data_factroy_init(); 
    sys_data_set_factory_reset(TRUE);
    sys_data_set_cur_chan_mode(TV_CHAN);
    sys_data_save(TRUE);

	recreate_tp_view(VIEW_SINGLE_SAT, 1);
	del_tp_on_sat(1);
	update_data();

	win_compopup_close();

	win_compopup_init(WIN_POPUP_TYPE_SMSG);
	win_compopup_set_msg_ext("Done! Rebooting...",NULL, NULL);
	win_compopup_open();
	osal_task_sleep(1500);
	libc_printf("%s\n",__FUNCTION__);
	OSD_ShowOnOff(OSDDRV_OFF);//weber@20091005 Avoid factory menu showing before reboot in factory menu when run "Exit/Set to Default"
    ap_send_msg(CTRL_MSG_SUBTYPE_CMD_REBOOT, 0, FALSE);
//	power_on_process();
}

#ifdef HDCP_IN_FLASH

/* file access */
//#include <api/libfs2/stat.h>
//#include <api/libfs2/dirent.h>
//#include <api/libfs2/statvfs.h>
#include <api/libfs2/unistd.h>
#include <api/libfs2/stdio.h>

#include <api/libchunk/chunk.h>
#include <api/libupg/usb_upgrade.h>

//#define HDCP_IN_FLASH
//#define HDCPKEY_CHUNK_ID 	(HDCPKEY_CHUNID_TYPE |0x0100)
#define AOV_HDCP_ID_FILE	"/c/aov_hdcp_key.idx"

#define FILE_IDX_SIZE 6
#define FILE_KEY_SIZE (280+5+1)  //40 set of 7 bytes key + 5 bytes KSV + 1 bytes leading by ALi

void AOV_Install_HDCP(void)
{
	UINT8 back_saved;

	int file_ret;
	INT32 file_length, idx, i;
	FILE *fp_idx=NULL, *fp_key=NULL;

	char *idxBuff, *keyBuff = NULL;
	char tmp_str[128];
	char key_filename[128];

   	UINT32 param;

	UINT32 hdcp_chuck_id = HDCPKEY_CHUNK_ID;		
	UINT8 *bootloader_sector = NULL;	
	CHUNK_HEADER boot_loader_chuck_hdr;
	UINT32 boot_loader_chuck_id = 0x0;		

	UINT8 *cptr;
	BOOL hdcp_is_installed=FALSE;

	//change state to USB_UPG
	system_state == SYS_STATE_USB_UPG;

	api_nim_disable();
	dm_set_onoff(0);
	/*mailen fix*/
	api_stop_play(0);
  	//UIChChgStopProg(FALSE);

	//try to close all OSD as many as possible
	ap_clear_all_menus();
	
	idxBuff = MALLOC(FILE_IDX_SIZE+1);
	keyBuff = MALLOC(FILE_KEY_SIZE);
	
	MEMSET(idxBuff, 0, FILE_IDX_SIZE+1);
	MEMSET(keyBuff, 0, FILE_KEY_SIZE);

	/* Read idx file to get index  */
	if(idxBuff == NULL)
	{
		libc_printf("Buff malloc error\n");
		key_pan_display("Err7", 4);
		goto hdcp_end;
	}

	fp_idx = fopen(AOV_HDCP_ID_FILE, "r");
	if(fp_idx == NULL)
	{
		sprintf(tmp_str, "Can't read %s\n",AOV_HDCP_ID_FILE);
		//win_compopup_close();
		
		win_compopup_init(WIN_POPUP_TYPE_OK);
		win_compopup_set_msg_ext(tmp_str,NULL,0);
		win_compopup_open_ext(&back_saved);
		if (back_saved)
			win_compopup_smsg_restoreback();
			
		key_pan_display("Err5", 4);
		FREE(idxBuff);
		goto hdcp_end;
	}
		
	file_ret = fread(idxBuff,FILE_IDX_SIZE,1,fp_idx);
	idxBuff[FILE_IDX_SIZE]='\n';
	idx=ali_atoi(idxBuff);
	if (idx<0)
	{
		sprintf(tmp_str,"Invalid HDCP Key Index\n");
		//libc_printf("%s\n",tmp_str);	
		key_pan_display("Err6", 4);
		win_compopup_init(WIN_POPUP_TYPE_OK);
		win_compopup_set_msg_ext(tmp_str,NULL,0);
		win_compopup_open_ext(&back_saved);
		if (back_saved)
			win_compopup_smsg_restoreback();
		fclose(fp_idx);
		goto hdcp_end;
	}

	//get corresponding key file
	sprintf(key_filename,"/c/SCR_HDCP_Key_%06d.bin",idx);
	
	fp_key = fopen(key_filename, "r");
	if(fp_key == NULL)
	{
		sprintf(tmp_str, "No HDCP Key file %s", key_filename);
		win_compopup_init(WIN_POPUP_TYPE_OK);
		win_compopup_set_msg_ext(tmp_str,NULL,0);
		win_compopup_open_ext(&back_saved);
		if (back_saved)
			win_compopup_smsg_restoreback();
		//libc_printf("%s\n",tmp_str);
		key_pan_display("Err8", 4);
		goto hdcp_end;
	}

	file_ret = fread(keyBuff,FILE_KEY_SIZE,1,fp_key);
	if (file_ret != FILE_KEY_SIZE)
	{
		sprintf(tmp_str, "Invalid HDCP Key file %s", key_filename);
		win_compopup_init(WIN_POPUP_TYPE_OK);
		win_compopup_set_msg_ext(tmp_str,NULL,0);
		win_compopup_open_ext(&back_saved);
		if (back_saved)
			win_compopup_smsg_restoreback();
		//libc_printf("%s\n",tmp_str);
		key_pan_display("Err9", 4);
		goto hdcp_end;
	}

	api_nim_disable();
	dm_set_onoff(0);
  	//UIChChgStopProg(FALSE);

#if (WATCH_DOG == SYS_FUNC_ON)
	//Dana, have to stop watchdog timer.
	//When task stop running, it will trigger watchdog and caused reboot
	UiClearWatchDog();
#endif				

	//Get bootloader, and write it back with HDCP key
	bootloader_sector = (UINT8 *)MALLOC(sizeof(UINT8)*64*1024);
	if(bootloader_sector != NULL)
	{
		//backup bootloader
		sto_lseek((struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0), 0, STO_LSEEK_SET);										
		sto_read((struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0), bootloader_sector, 64*1024);
		//check if already had HDCP installed
		cptr = (bootloader_sector+0xfe00+CHUNK_HEADER_SIZE);
		for (i=0; i<FILE_KEY_SIZE; i++)
		if (*cptr!=0xFF)
		{
			hdcp_is_installed=TRUE;
			break;
		}

		if (hdcp_is_installed)
		{
			win_popup_choice_t choice;
			win_compopup_init(WIN_POPUP_TYPE_OKNO);
			win_compopup_set_default_choice(WIN_POP_CHOICE_NO);
			win_compopup_set_msg_ext("HDCP key already installed. Reload again?", NULL, NULL);
			choice = win_compopup_open_ext(&back_saved);
			if(choice == WIN_POP_CHOICE_NO)
				goto hdcp_end;
			if (back_saved)
				win_compopup_smsg_restoreback();
		}	
			
		//clear HDCP partition
		MEMSET(bootloader_sector+0xfe00+CHUNK_HEADER_SIZE, 0xFF, 384);

		//copy HDCP key buffer to boot loader area				
		MEMCPY(bootloader_sector+0xFE00+CHUNK_HEADER_SIZE ,keyBuff,FILE_KEY_SIZE);		

		//erase STB flash
   		/* Uper 22 bits of MSB is start offset based on SYS_FLASH_BASE_ADDR */
   		param = 0;
   		/* Lower 10 bits of LSB is length in K bytes*/
   		param += SECTOR_SIZE >> 10;
			
		osal_task_dispatch_off();
   		if(sto_io_control((struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0), STO_DRIVER_SECTOR_ERASE, param) != SUCCESS)
   		{
			sprintf(tmp_str, "Erase flash memory failed");
			win_compopup_init(WIN_POPUP_TYPE_OK);
			win_compopup_set_msg_ext(tmp_str,NULL,0);
			win_compopup_open_ext(&back_saved);
			if (back_saved)
				win_compopup_smsg_restoreback();
			key_pan_display("ErrB", 4);
			osal_task_dispatch_on();
			goto hdcp_end;
        }
		else
		{	
			//write bootloader with new HDCP key
			sto_lseek((struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0), 0, STO_LSEEK_SET);								
			sto_write((struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0), bootloader_sector,64*1024);									
		}			
		osal_task_dispatch_on();	
		FREE(bootloader_sector);	
	}

	fp_idx = fopen(AOV_HDCP_ID_FILE, "w");
	//increase idx in aov_hdcp_key.idx, and write back to USB disk
	idx++;
	sprintf(idxBuff,"%04d", idx);

	//libc_printf("write %s to %s\n",idxBuff, AOV_HDCP_ID_FILE);
	if (fwrite(idxBuff, FILE_IDX_SIZE, 1, fp_idx)==0)
	{
		libc_printf("Write fail\n");
		goto hdcp_end;
	}

#if 1//ChengYu@	
	fclose(fp_idx);
	fs_sync("/c/");
#endif

	sprintf(tmp_str,"HDCP Installed idx=%04d.\nSystem Halt!",idx-1);
	win_compopup_init(WIN_POPUP_TYPE_OK);
	win_compopup_set_msg_ext(tmp_str,NULL,0);
	win_compopup_open_ext(&back_saved);
	if (back_saved)
		win_compopup_smsg_restoreback();
		
	key_pan_display(" OK ", 4);
	while(1);

hdcp_end:						

	if (fp_idx!=NULL && fp_key!=NULL)
	{
		//sprintf(tmp_str,"/c/%s",AOV_HDCP_ID_FILE);	
		//fs_remove(tmp_str);
		fs_sync("/c/");		
		usb_fs_unmount(0);
	}
		
	fclose(fp_idx);
	fclose(fp_key);
	FREE(idxBuff);
	FREE(keyBuff);
}
#endif


//ChengYu@20140221, for fast upgrade, valid only in welcome page	
//check if in welcome page, if yes, check fast upgrade
//force into upgrade menu whenever USB plugged
void AOV_Fast_Upgrade_Check(void)
{
	PRESULT proc_ret=PROC_PASS;

	RET_CODE ret;
	UINT16 usb_blk_cnt=0, usb_fastfile_cnt=0;

	//CHENGYU_PRINTF("enter fast upgrade check\n");
	b_fast_upgrade = TRUE;
	if(usbupg_block_init(&usb_blk_cnt) == RET_FAILURE)
	{
		usbupg_block_free();
		CHENGYU_PRINTF("usbupg_block_init fail\n");	
		return proc_ret;;
	}

	//Check fast upgrade file existed first
	ret = usbupg_create_filelist(0,&usb_fastfile_cnt);
	if (usb_fastfile_cnt>0) //if there is fast upgrade file
	{
		//Switch to usbupg
		system_state = SYS_STATE_USB_UPG;
		key_pan_display("FUPG",4);
		proc_ret = OSD_ObjOpen(&win_usbupg_con, MENU_OPEN_TYPE_STACK);
		if(proc_ret != PROC_LEAVE)
		{
			menu_stack_push(&win_usbupg_con);
			ap_send_msg_to_top_menu(&win_usbupg_con, CTRL_MSG_SUBTYPE_KEY, V_KEY_FAST_UPG);
		}
	}
	else
		CHENGYU_PRINTF("No fast upgrade file\n");

	b_fast_upgrade = FALSE;
	system_state = SYS_STATE_NORMAL;
	return proc_ret;
}


void ap_enter_factory_test(void)
{
	UINT8 back_saved;
	SYSTEM_DATA *sys_data = sys_data_get();

	if (Factory_Mode_Get_Flag() == FALSE)
	{
		CHENGYU_PRINTF("ap_enter_factory_test ==> OFF->ON\n");
		sys_data->factory_mode = TRUE;
		Factory_Mode_Set_Flag(TRUE);
		ap_clear_all_message();
		ap_clear_all_menus();
		win_compopup_init(WIN_POPUP_TYPE_SMSG);
		win_compopup_set_msg_ext("Enter factory mode", NULL, 0);
		win_compopup_open_ext(&back_saved);
		osal_task_sleep(1000);
		win_compopup_smsg_restoreback();
		ap_send_msg(CTRL_MSG_SUBTYPE_CMD_ENTER_ROOT,(UINT32)&g_win_factory_test, TRUE);
	}
	else
	{
		CHENGYU_PRINTF("ap_enter_factory_test ==> ON->OFF\n");
		sys_data->factory_mode = FALSE;
		Factory_Mode_Set_Flag(FALSE);		
		win_compopup_init(WIN_POPUP_TYPE_SMSG);
		win_compopup_set_msg_ext("Exit factory mode", NULL, 0);
		win_compopup_open_ext(&back_saved);
		osal_task_sleep(1000);
		win_compopup_smsg_restoreback();
	}
	sys_data_save(1);
}


BOOL Factory_Func(UINT32 vkey)
{	
	BOOL ret = FALSE;
	//CHENGYU_PRINTF("Factory_Func ==> vkey(%u)\n",vkey);
    switch (vkey)
	{
		case V_KEY_MENU:
		{
			//whenever "FAV" pressed, re-trigger
			History_Idx=0;
			KeyEnabled = TRUE;
			memset(key_history,0, MAX_HISTORY+1);
		} break;

		case V_KEY_0: case V_KEY_1: case V_KEY_2:
		case V_KEY_3: case V_KEY_4: case V_KEY_5:
		case V_KEY_6: case V_KEY_7: case V_KEY_8:
		case V_KEY_9:
		{
            //vkey = Aov_Factory_Convert_VKey( vkey );
			if (KeyEnabled)	
			{                            
				/*mailen@avoid system crashing*/
				POBJECT_HEAD topmenu = menu_stack_get_top();
				if ((Factory_Mode_Get_Flag() == FALSE && topmenu != &g_win_mainmenu && topmenu != &g_win_welcom) ||
					(Factory_Mode_Get_Flag() == TRUE && topmenu == NULL))
				{
					KeyEnabled = FALSE;
					break;
				}
		  		key_history[History_Idx++]=(char)vkey+0x30;
				//key_history[MAX_HISTORY]=0;
		  		if (History_Idx == MAX_HISTORY)
		  		{
					KeyEnabled = FALSE;

					if (STRCMP(key_history, "789052")==0)
					{
						ap_enter_factory_test();

						ret=TRUE;
					}
		  		}
			}
		}
		break;
		default:
			KeyEnabled = FALSE;
			break;
	}
	return ret;
}

//steven(2008/12/08): TT#558 Factory test functions.[End]

